#=============================================================================
#
# Copyright 2007 Adam Wisniewski <adamw@tbcn.ca> 
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at 
#
#  http://www.apache.org/licenses/LICENSE-2.0 
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
#=============================================================================

require 'digest/md5'
require 'cached_call'

module CallCache
  
    CACHE_DIRECTORY = "/tmp/cache"
    SECONDS_TO_CACHE = 60 * 60 * 3
        
    def CallCache.call( function_call, hashes )
        parameters = hashes[:pars]
        options = hashes[:options]
        
        ttl = SECONDS_TO_CACHE
        if !options.nil?
            if options[:ttl]
                ttl = options[:ttl]
            end
        end

        cached_call = CallCache.find( function_call, *parameters )
        
        if cached_call == nil || Time.now.to_i - cached_call.created_at.to_i > ttl
            return_val = CallCache.make_call( function_call, *parameters )
            cached_call = CachedCall.new( return_val, function_call, *parameters )
            
            CallCache.save( cached_call )
        end

        return cached_call.return_val          
    end
    
    def CallCache.get_id_for( function_call, *parameters)
        md5 = Digest::MD5::new
        md5.update( function_call.gsub('::', '_').gsub('.', '_') )
        md5.update( Marshal.dump( parameters ) )
        return md5.hexdigest   
    end

    #def CallCache.check_or_create_tmp_dir
    #    file_path = CallCache::CACHE_DIRECTORY + File::SEPARATOR + "call_cache_" + id_string
    #end

    def CallCache.file_path_for( function_call, *parameters )
        CallCache::CACHE_DIRECTORY + File::SEPARATOR + 
                        "call_cache_" + CallCache.get_id_for( function_call, *parameters )
    end

    def CallCache.find( function_call, *parameters )
        cached_call = nil

        file_path = CallCache.file_path_for(function_call, *parameters)

        if File.exist?( file_path )
            # return saved cached result
            cached_call = Marshal.load( File.read( file_path ) )
        end

        return cached_call
    end

    def CallCache.save( cached_call )
        # write call to cache location

        if !File.directory?( CallCache::CACHE_DIRECTORY )
            Dir.mkdir( CallCache::CACHE_DIRECTORY )
        end

        file_path = CallCache.file_path_for( cached_call.function_call, *cached_call.parameters )
        dest_file = File.new( file_path, 'wb' )
        dest_file.write( Marshal.dump( cached_call ) )
        dest_file.close

    end

    def CallCache.make_call( function_call, *parameters )
          # call function
          # parse call to handle local methods or static class methods 
          function_call.gsub!( '::', '.' )
          function_call_split = function_call.split(/\./)
          # make the call

          return_val = eval( function_call_split[0..-2].join('::') ).method( function_call_split[-1] ).call( *parameters )          

      end
end
